package jobase

import (
	"gitee.com/jolib/jokode/joth"
)

type Queue[T any] struct {
	locker   joth.IRWLocker
	dataList *LinkList[T]
}

func NewSafeQueue[T any]() *Queue[T] {
	return &Queue[T]{
		locker:   joth.NewRWLocker(),
		dataList: NewLinkList[T](),
	}
}

func NewUnsafeQueue[T any]() *Queue[T] {
	return &Queue[T]{
		locker:   new(joth.NoneRWLocker),
		dataList: NewLinkList[T](),
	}
}

func (q *Queue[T]) Empty() bool {
	q.locker.RLock()
	defer q.locker.RUnlock()

	return q.dataList.Len() == 0
}

func (q *Queue[T]) EnQueue(value T) {
	q.locker.Lock()
	defer q.locker.Unlock()

	q.dataList.PushBack(value)
}

func (q *Queue[T]) DeQueue() (v T, ok bool) {
	q.locker.Lock()
	defer q.locker.Unlock()

	if n := q.dataList.Front(); n != nil {
		q.dataList.Remove(n)
		v = n.Data()
		ok = true
	}

	return
}

func (q *Queue[T]) GetHead() (v T, ok bool) {
	q.locker.RLock()
	defer q.locker.RUnlock()

	if n := q.dataList.Front(); n != nil {
		v = n.Data()
		ok = true
	}

	return
}

func (q *Queue[T]) GetTail() (v T, ok bool) {
	q.locker.RLock()
	defer q.locker.RUnlock()

	if n := q.dataList.Back(); n != nil {
		v = n.Data()
		ok = true
	}

	return
}

func (q *Queue[T]) Reset() {
	q.locker.Lock()
	defer q.locker.Unlock()

	if q.dataList.Len() > 0 {
		old := q.dataList
		q.dataList = NewLinkList[T]()

		go func(l *LinkList[T]) {
			for n := l.Front(); n != nil; n = l.Front() {
				l.Remove(n)
			}
		}(old)
	}
}

func (q *Queue[T]) Size() int {
	q.locker.RLock()
	defer q.locker.RUnlock()

	return q.dataList.Len()
}
